导航菜单
首页 >  Flutter 小技巧之 Flutter 3 下的 ThemeExtensions  > Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套

Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套

这次的 Flutter 小技巧是 ​​ListView​​​ 和 ​​PageView​​​ 的花式嵌套,不同 ​​Scrollable​​​ 的嵌套冲突问题相信大家不会陌生,今天就通过 ​​ListView​​​ 和 ​​PageView​​ 的三种嵌套模式带大家收获一些不一样的小技巧。

正常嵌套

最常见的嵌套应该就是横向 ​​PageView​​​ 加纵向 ​​ListView​​ 的组合,一般情况下这个组合不会有什么问题,除非你硬是要斜着滑。

最近刚好遇到好几个人同时在问:“斜滑 ​​ListView​​​ 容易切换到 ​​PageView​​​ 滑动” 的问题,如下 GIF 所示,当用户在滑动​​ListView​​​时,滑动角度带上倾斜之后,可能就会导致滑动的是​​PageView​​​而不是 ​​ListView​​ 。

Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套_ide

虽然从我个人体验上并不觉得这是个问题,但是如果产品硬是要你修改,难道要自己重写 ​​PageView​​的手势响应吗?

我们简单看一下,不管是 ​​PageView​​​还是​​ListView​​​ 它们的滑动效果都来自于 ​​Scrollable​​​ ,而​​Scrollable​​​ 内部针对不同方向的响应,是通过 ​​RawGestureDetector​​ 完成:

​​VerticalDragGestureRecognizer​​ 处理垂直方向的手势​​HorizontalDragGestureRecognizer​​ 处理水平方向的手势

所以简单看它们响应的判断逻辑,可以看到一个很有趣的方法 ​​computeHitSlop​​ : 根据 pointer 的类型确定当然命中需要的最小像素,触摸默认是 kTouchSlop (18.0)。

Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套_前端_02

看到这你有没有灵光一闪:如果我们把 ​​PageView​​ 的 touchSlop 修改了,是不是就可以调整它响应的灵敏度? 恰好在 ​​computeHitSlop​​​ 方法里,它可以通过 ​​DeviceGestureSettings​​​ 来配置,而 ​​DeviceGestureSettings​​​ 来自于 ​​MediaQuery​​ ,所以如下代码所示:

body: MediaQuery( ///调高 touchSlop 到 50 ,这样 pageview 滑动可能有点点影响, ///但是大概率处理了斜着滑动触发的问题 data: MediaQuery.of(context).copyWith( gestureSettings: DeviceGestureSettings(touchSlop: 50, )), child: PageView(scrollDirection: Axis.horizontal,pageSnapping: true,children: [ HandlerListView(), HandlerListView(),], ),),

小技巧一:通过嵌套一个 ​​MediaQuery​​ ,然后调整 ​​gestureSettings​​ 的 ​​touchSlop​​ 从而修改 ​​PageView​​ 的灵明度 ,另外不要忘记,还需要把 ​​ListView​​​ 的​​touchSlop​​​ 切换会默认 的 ​​kTouchSlop​​ :

class HandlerListView extends StatefulWidget{ @override _MyListViewState createState() => _MyListViewState();}class _MyListViewState extends State { @override Widget build(BuildContext context) {return MediaQuery( ///这里 touchSlop 需要调回默认 data: MediaQuery.of(context).copyWith( gestureSettings: DeviceGestureSettings(touchSlop: kTouchSlop, )), child: ListView.separated(itemCount: 15,itemBuilder: (context, index) { return ListTile(title: Text('Item $index'), );},separatorBuilder: (context, index) { return const Divider(thickness: 3, );}, ),); }}

最后我们看一下效果,如下 GIF 所示,现在就算你斜着滑动,也很触发 ​​PageView​​​ 的水平滑动,只有横向移动时才会触发​​PageView​​ 的手势,当然, 如果要说这个粗暴的写法有什么问题的话,大概就是降低了​​PageView​​响应的灵敏度。

Flutter 小技巧之 ListView 和 PageView 的各种花式嵌套_前端_03

同方向 PageView 嵌套 ListView

介绍完常规使用,接着来点不一样的,在垂直切换的 ​​PageView​​ 里嵌套垂直滚动的 ​​ ListView​​ , 你第一感觉是不是觉得不靠谱,为什么会有这样的场景?

对于产品来说,他们不会考虑你如何实现的问题,他们只会拍着脑袋说淘宝可以,为什么你不行,所以如果是你,你会怎么做?

而关于这个需求,社区目前讨论的结果是:把 ​​PageView​​ 和 ​​ListView​​ 的滑动禁用,然后通过 ​​RawGestureDetector​​ 自己管理。

如果对实现逻辑分析没兴趣,可以直接看本小节末尾的 ​​源码

相关推荐: